#include<stdio.h>
#include<malloc.h>

typedef struct node Node;
typedef struct queue Queue;

struct node{
	int data;
	Node *next;
};

struct queue{
	Node *front, *rear;
	int size;
	int limit;
};

Queue *CreateQueue(int);
int EnQueue(Queue *, int);
int DeQueue(Queue *);
int isQueueEmpty(Queue *);
int isQueueFull(Queue *);
int QueueSize(Queue *);

void debugPrintList(Queue *);


int main(){
	int i = 0, data;
	Queue *q;
	q = CreateQueue(5);
	for(i = 0; i < 6; i++){
		if(EnQueue(q, i*2+1)){
			printf("\nSuccessfully pushed %d to the Queue!", i*2+1);
		}else{
			printf("\nPushing %d failed! QueueFull:%s", i*2+1, isQueueFull(q)?"True":"False");
		}
	}
	
	debugPrintList(q);
	
	printf("\nPulling out stuff!");
	for(i = 0; i < 6; i++){
		if(data = DeQueue(q)){
			printf("\nGot data %d from the Queue! And QueueSize: %d", data, QueueSize(q));
		}else{
			printf("\nError in fetching data! QueueEmpty=%s and QueueSize=%d", isQueueEmpty(q)?"True":"False", QueueSize(q));
		}
	}
	
	printf("\n---Queue using Linked Lists\n");
	return 0;
}

Queue *CreateQueue(int lim){
	Queue *Q = (Queue *)malloc(sizeof(Queue));
	if(!Q){
		return NULL;
	}
	Q->front = NULL;
	Q->rear = NULL;
	Q->size = 0;
	Q->limit = lim;
	return Q;
}

int EnQueue(Queue *Q, int data){
	if(isQueueFull(Q)){
		return 0;
	}
	Node *newNode = (Node *)malloc(sizeof(Node));
	if(!newNode){
		return 0;
	}
	newNode->data = data;
	newNode->next = NULL;
	if(Q->front == NULL){
		Q->front = newNode;	//if no front, then make this, the front
	}
	if(Q->rear != NULL){
		Q->rear->next = newNode;	//if has rear, then link that to this
	}
	Q->rear = newNode;	//move the rear
	Q->size++;
	return 1;
}

int DeQueue(Queue *Q){
	if(isQueueEmpty(Q)){
		return 0;
	}
	int data;
	data = Q->front->data;
	Node *thisNode = Q->front;
	Q->front = thisNode->next;
	free(thisNode);
	Q->size--;
	return data;
}

int isQueueEmpty(Queue *Q){
	return (Q->front == NULL);
}

int isQueueFull(Queue *Q){
	return (Q->size == Q->limit);
}

int QueueSize(Queue *Q){
	return Q->size;
}

void debugPrintList(Queue *Q){
	printf("\n--DEBUG: Printing List--\n");
	Node *head = Q->front;
	while(head){
		printf("\nNode Value: %d", head->data);
		head = head->next;
	}
	printf("\n--DEBUG: Print list end--\n");
}
